package com.bizmda.bizsip.sample.source.longtcpnetty;

import com.bizmda.bizsip.common.BizException;
import com.bizmda.bizsip.common.BizResultEnum;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * @author: 史正烨
 * @date: 2022/3/1 11:25 上午
 * @Description:
 */
@Component
@Slf4j
public class NettyClient {
    private final EventLoopGroup group = new NioEventLoopGroup();
    private SocketChannel channel = null;
    private Bootstrap bootstrap;
    @Value("${long-tcp-netty.source-netty-client-port}")
    private int nettyPort;

    @Value("${long-tcp-netty.source-netty-client-host}")
    private String host;

    @PostConstruct
    public void start() {
        this.bootstrap = new Bootstrap();
        this.bootstrap.group(this.group)
                .channel(NioSocketChannel.class)
                //设置TCP长连接,一般如果两个小时内没有数据的通信时,TCP会自动发送一个活动探测数据报文
//                .option(ChannelOption.SO_KEEPALIVE, true)
                //将小的数据包包装成更大的帧进行传送，提高网络的负载
                .option(ChannelOption.TCP_NODELAY, true)
                .handler(new ClientChannelInitializer())
        ;
        ChannelFuture future;
        try {
            future = this.bootstrap.connect(host, nettyPort).sync();
        } catch (InterruptedException e) {
            log.warn("Interrupted!",e);
            Thread.currentThread().interrupt();
            return;
        }
        catch (Exception e) {
            log.error("启动Netty失败!",e);
            return;
        } finally {
//            this.group.shutdownGracefully();
        }
        if (future.isSuccess()) {
            log.info("启动 Netty 成功");
        }
        this.channel = (SocketChannel) future.channel();
    }

    public void sendData(byte[] bytes) throws BizException {
        if (this.channel == null || (!this.channel.isActive())) {
            try {
                ChannelFuture future = this.bootstrap.connect(host, nettyPort).sync();
                if (!future.isSuccess()) {
                    throw new BizException(BizResultEnum.OTHER_ERROR,"启动 Netty 失败!");
                }
                this.channel = (SocketChannel) future.channel();
            }
            catch (InterruptedException e) {
                log.warn("Interrupted!",e);
                Thread.currentThread().interrupt();
            }
            catch (Exception e) {
                throw new BizException(BizResultEnum.OTHER_ERROR,e);
            }finally {
//                this.group.shutdownGracefully();
            }
        }

        SampleMessage sampleMessage = SampleMessage.builder()
                .length((short)bytes.length)
                .data(bytes).build();
        this.channel.writeAndFlush(sampleMessage);
    }
}